package metricx

import (
	"context"
	"time"

	"github.com/todo/toolx/utilx/otlex"
	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
	"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
	"go.opentelemetry.io/otel/sdk/metric"
	"google.golang.org/grpc/credentials"
)

type Config otlex.ExporterConfig

type ConfigHandle = func(config *Config)

func (config Config) NewExporter(ctx context.Context, handles ...ConfigHandle) (metric.Exporter, error) {
	for _, handle := range handles {
		handle(&config)
	}

	switch config.Type {
	case otlex.Grpc:
		options := make([]otlpmetricgrpc.Option, 0, 1<<3)
		options = append(options,
			otlpmetricgrpc.WithEndpoint(config.Endpoint),
			otlpmetricgrpc.WithHeaders(config.Headers),
			otlpmetricgrpc.WithTimeout(time.Second*time.Duration(config.Timeout)),
			otlpmetricgrpc.WithRetry(otlpmetricgrpc.RetryConfig{
				Enabled:         config.Retry.Enabled,
				InitialInterval: config.Retry.InitialInterval,
				MaxInterval:     config.Retry.MaxInterval,
				MaxElapsedTime:  config.Retry.MaxElapsedTime,
			}),
			otlpmetricgrpc.WithReconnectionPeriod(time.Second*time.Duration(config.ReconnectionPeriod)),
			otlpmetricgrpc.WithServiceConfig(config.ServiceConfig),
		)

		if config.Compression {
			options = append(options, otlpmetricgrpc.WithCompressor("gzip"))
		}

		if config.Insecure {
			options = append(options, otlpmetricgrpc.WithInsecure())
		}

		if !config.Insecure && config.TLS.IsEnable() {
			options = append(options, otlpmetricgrpc.WithTLSCredentials(credentials.NewTLS(config.TLS.Tls())))
		}

		return otlpmetricgrpc.New(ctx, options...)
	case otlex.Http:
		options := make([]otlpmetrichttp.Option, 0, 1<<3)
		options = append(options, otlpmetrichttp.WithEndpointURL(config.Endpoint),
			otlpmetrichttp.WithHeaders(config.Headers),
			otlpmetrichttp.WithTimeout(time.Second*time.Duration(config.Timeout)),
			otlpmetrichttp.WithRetry(otlpmetrichttp.RetryConfig{
				Enabled:         config.Retry.Enabled,
				InitialInterval: config.Retry.InitialInterval,
				MaxInterval:     config.Retry.MaxInterval,
				MaxElapsedTime:  config.Retry.MaxElapsedTime,
			}),
		)

		if config.Compression {
			options = append(options, otlpmetrichttp.WithCompression(1))
		}

		if config.Insecure {
			options = append(options, otlpmetrichttp.WithInsecure())
		}

		if !config.Insecure && config.TLS.IsEnable() {
			options = append(options, otlpmetrichttp.WithTLSClientConfig(config.TLS.Tls()))
		}

		if len(config.URLPath) > 0 {
			options = append(options, otlpmetrichttp.WithURLPath(config.URLPath))
		}

		return otlpmetrichttp.New(ctx, options...)
	case otlex.Stdout:
		return stdoutmetric.New(
			stdoutmetric.WithoutTimestamps(),
			stdoutmetric.WithPrettyPrint(),
		)
	default:
		return nil, otlex.NotFoundType
	}
}
